package pages;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import database.DBUtils;
import database.DBException;

import templates.Template;

/**
 * Servlet implementation class Register
 */
public class Register extends HttpServlet {
	private static final long serialVersionUID = 1L;

	private static final String pageTitle = "Register";

	private static final String templateName = "register";
	private static final String groupsTemplateName = "groups_combo";
	private static final String groupsOptionTemplateName = "group_option";

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public Register() {
		super();
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		try {
			response.getWriter().print(loadRegisterPage(request));
		} catch (Exception e) {
			ErrorPage.printErrorPage(e.getMessage(), request, response);
		}
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		String error = "";
		try {
			LMUtils.setRequestAttribute(request, "newUserLogin", LMUtils
					.getRequestParameterValueNotEmpty(request, "login"));
			LMUtils.setRequestAttribute(request, "newUserLoginError", "");
		} catch (MissingParameterException e) {
			error = "Please fill in all required fields (marked with *) ";
			LMUtils.setRequestAttribute(request, "newUserLoginError",
					"This field is required");
		}
		try {
			LMUtils.setRequestAttribute(request, "newUserPassword", LMUtils
					.getRequestParameterValueNotEmpty(request, "password"));
			LMUtils.setRequestAttribute(request, "newUserPasswordError", "");
		} catch (MissingParameterException e) {
			error = "Please fill in all required fields (marked with *) ";
			LMUtils.setRequestAttribute(request, "newUserPasswordError",
					"This field is required");
		}
		try {
			LMUtils.setRequestAttribute(request, "newUserCPassword", LMUtils
					.getRequestParameterValueNotEmpty(request, "c_password"));
			if (!LMUtils.getRequestAttribute(request, "newUserCPassword")
					.equals(
							LMUtils.getRequestAttribute(request,
									"newUserPassword"))) {
				error = "The passwords don't match";
			}
			LMUtils.setRequestAttribute(request, "newUserCPasswordError", "");
		} catch (MissingParameterException e) {
			error = "Please fill in all required fields (marked with *) ";
			LMUtils.setRequestAttribute(request, "newUserCPasswordError",
					"This field is required");
		}
		try {
			LMUtils.setRequestAttribute(request, "newUserName", LMUtils
					.getRequestParameterValueNotEmpty(request, "name"));
			LMUtils.setRequestAttribute(request, "newUserNameError", "");
		} catch (MissingParameterException e) {
			error = "Please fill in all required fields (marked with *) ";
			LMUtils.setRequestAttribute(request, "newUserNameError",
					"This field is required");
		}
		try {
			LMUtils.setRequestAttribute(request, "newUserGroupOwnerLogin",
					LMUtils.getRequestParameterValue(request, "group"));
			LMUtils.setRequestAttribute(request, "groupError", "");
		} catch (MissingParameterException e) {
			error = "Please fill in all required fields (marked with *) ";
			LMUtils.setRequestAttribute(request, "groupError",
					"This field is required");
		}
		try {
			LMUtils.getRequestParameterValueNotEmpty(request, "ask_for_admin");
			LMUtils.setRequestAttribute(request, "isAskedForAdmin", true);
		} catch (MissingParameterException e) {
			LMUtils.setRequestAttribute(request, "isAskedForAdmin", false);
		}

		// if any input error occurred
		if (!error.equals("")) {
			doGet(request, response);
		} else {
			Connection conn = null;
			PreparedStatement insertStmt = null;
			try {
				try {
					conn = DBUtils.getConnection();
					String groupOwnerLogin = LMUtils.getRequestAttribute(
							request, "newUserGroupOwnerLogin");
					// TODO: check existence of the group
					if (Boolean.parseBoolean(LMUtils.getRequestAttribute(
							request, "isAskedForAdmin"))) {
						groupOwnerLogin = "";
					} else if (groupOwnerLogin.isEmpty()) {
						groupOwnerLogin = LMUtils.getRequestAttribute(request,
								"newUserLogin");
					}

					String usersTableName = LMUtils.getContextParameterValue(
							getServletContext(), "db.UsersTableName");
					String rolesTableName = LMUtils.getContextParameterValue(
							getServletContext(), "db.RolesTableName");
					insertStmt = conn
							.prepareStatement("INSERT INTO `"
									+ usersTableName
									+ "` (`Login`, `Password`, `Name`, `groupOwnerLogin`, `Phone`, `Address`)"
									+ " VALUES (?, MD5(?), ?, ?, '', '');");
					insertStmt.setString(1, LMUtils.getRequestAttribute(
							request, "newUserLogin"));
					insertStmt.setString(2, LMUtils.getRequestAttribute(
							request, "newUserPassword"));
					insertStmt.setString(3, LMUtils.getRequestAttribute(
							request, "newUserName"));
					insertStmt.setString(4, groupOwnerLogin);

					insertStmt.execute();

					// inserting role
					insertStmt = conn.prepareStatement("INSERT INTO `"
							+ rolesTableName
							+ "` (`Login`, `Role`, `RealRole`)"
							+ " VALUES (?, ?, ?);");
					// if the user asked to be an admin he will be inactive
					// until another admin activates him
					insertStmt.setString(1, LMUtils.getRequestAttribute(
							request, "newUserLogin"));
					insertStmt.setString(2,
							Boolean.parseBoolean(LMUtils.getRequestAttribute(
									request, "isAskedForAdmin")) ? "BLOCKED"
									: "RESEARCHER");
					insertStmt.setString(3,
							Boolean.parseBoolean(LMUtils.getRequestAttribute(
									request, "isAskedForAdmin")) ? "ADMIN"
									: "RESEARCHER");
					insertStmt.execute();

					Template successRegister = new Template("successRegister");
					response.getWriter().print(
							successRegister.createPage("Success Register",
									LMUtils.getUserLogin(request)));
					return;
				} catch (DBException e) {
					error = e.getMessage();
				} catch (InternalErrorException e) {
					error = e.getMessage();
				} catch (SQLException e) {
					if (e.getMessage().indexOf("Duplicate entry") >= 0) {
						error = "This login is already known to the system";
					} else {
						error = "Can't register: " + e.getMessage();
					}
					LMUtils.setRequestAttribute(request, "newUserLoginError",
							error);
				}
				LMUtils.setRequestAttribute(request, "error", error);
				doGet(request, response);

			} finally {
				DBUtils.close(insertStmt);
				DBUtils.close(conn);

			}
		}
	}

	/**
	 * Loads login page
	 * 
	 * @throws DBException
	 */
	private String loadRegisterPage(HttpServletRequest request)
			throws DBException, InternalErrorException {
		Template template = new Template(templateName);
		template.addChange("groups_combo", loadGroupsCombo(LMUtils
				.getRequestAttribute(request, "newUserGroupOwnerLogin")));
		template.addChange("error", LMUtils.getRequestAttribute(request,
				"error"));
		template.addChange("loginValue", LMUtils.getRequestAttribute(request,
				"newUserLogin"));
		template.addChange("nameValue", LMUtils.getRequestAttribute(request,
				"newUserName"));
		template.addChange("adminChecked",
				Boolean.parseBoolean(LMUtils.getRequestAttribute(request,
						"isAskedForAdmin")) ? "checked=\"checked\"" : "");

		template.addChange("loginError", LMUtils.getRequestAttribute(request,
				"newUserLoginError"));
		template.addChange("passwordError", LMUtils.getRequestAttribute(
				request, "newUserPasswordError"));
		template.addChange("c_passwordError", LMUtils.getRequestAttribute(
				request, "newUserCPasswordError"));
		template.addChange("nameError", LMUtils.getRequestAttribute(request,
				"newUserNameError"));
		template.addChange("groupError", LMUtils.getRequestAttribute(request,
				"groupError"));
		return template.createPage(pageTitle, LMUtils.getUserLogin(request));
	}

	/**
	 * Loads all the groups from DB and generates combo-box
	 * 
	 * @param selectedUserGroupOwnerLogin
	 * @return
	 * @throws DBException
	 * @throws InternalErrorException
	 */
	private String loadGroupsCombo(String selectedUserGroupOwnerLogin)
			throws DBException, InternalErrorException {
		Connection conn = null;
		PreparedStatement selectGroupsStmt = null;
		ResultSet rs = null;
		try {
			Template groupComboTemplate = new Template(groupsTemplateName);
			Template groupOptionTemplate = new Template(
					groupsOptionTemplateName);
			String groupOptionsText = "";

			conn = DBUtils.getConnection();
			String usersTableName = LMUtils.getContextParameterValue(
					getServletContext(), "db.UsersTableName");

			selectGroupsStmt = conn
					.prepareStatement("SELECT `Login`, `Name` FROM `"
							+ usersTableName
							+ "` WHERE `Login` = `groupOwnerLogin` AND `groupOwnerLogin` <> \"\" "
							+ " UNION (SELECT \"\" as `Login`, \"Create your own group\" as `Name`);");

			rs = selectGroupsStmt.executeQuery();

			while (rs.next()) {
				String groupOwnerLogin = rs.getString("Login");
				String groupName = rs.getString("Name");
				String selected = groupOwnerLogin
						.equals(selectedUserGroupOwnerLogin) ? "selected=\"selected\""
						: "";
				groupOptionTemplate.addChange("groupOwnerLogin",
						groupOwnerLogin);
				groupOptionTemplate.addChange("group_name", groupName);
				groupOptionTemplate.addChange("selected", selected);
				groupOptionsText += groupOptionTemplate.applyChanges();
			}

			groupComboTemplate.addChange("groups_options", groupOptionsText);

			return groupComboTemplate.applyChanges();

		} catch (SQLException e) {
			throw new DBException("Can't load Groups combo:" + e.getMessage(),
					e);
		} catch (Exception e) {
			throw new DBException("Can't load Groups combo:" + e.getMessage(),
					e);
		} finally {
			DBUtils.close(rs);
			DBUtils.close(selectGroupsStmt);
			DBUtils.close(conn);
		}
	}
}
